package edu.xidian.onlinedocument.utils.ot.internal.operations;

import com.google.common.collect.Lists;
import edu.xidian.onlinedocument.entity.OperationData;
import edu.xidian.onlinedocument.utils.ot.json.OperationClass;
import edu.xidian.onlinedocument.utils.ot.json.OperationNameToClass;
import lombok.Data;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.LinkedList;
import java.util.List;

@Data
public class ChangesList{

    /**
     * 版本号
     */
    private int revision;

    /**
     * 操作序列
     */
    private List<Change> changes;

    /*
    public ChangesList(Iterable<Change> changes) {
        this.changes = Lists.newArrayList(changes);
    }
     */
    public ChangesList() {
        this.changes = new LinkedList<>();
        revision = 0;
    }

    public ChangesList(List<Change> changes) {
        this.changes = Lists.newLinkedList(changes);
        revision = 0;
    }

    public ChangesList(Change[] changes, int revision) {
        // this()调用类内的其他构造函数
        this(Arrays.asList(changes), revision);
    }

    public ChangesList(List<Change> changes, int revision) {
        this.changes = Lists.newLinkedList(changes);
        this.revision = revision;
    }

    public List<Change> getChanges() {
        return changes;
    }

    /**
     * 向操作序列里加入一个操作
     * @param change 操作
     */
    public void addChange(Change change) {
        changes.add(change);
    }

    public void setRevision(int revision) {
        this.revision = revision;
    }

    public int getRevision() {
        return revision;
    }
    /*
    @Override
    public Text apply(int position, Text text) {
        for (Change change:
             changes) {
            change.apply(position, text);
            position += change.offset();
        }
        return text;
    }
     */

    /*
    @Override
    public Integer offset() {
        int pos = 0;
        int offset = 0;
        for (Change change:
             changes) {
            offset = change.offset();
            if(ChangeType.isDelete(change)) {
                offset = -offset;
            }
            pos += offset;
        }
        return pos;
    }
     */

    @Override
    public String toString() {
        String str = "{ revision=" + revision;
        for (Change c:
             changes) {
            str += ", " + c;
        }
        str += " }";
        return str;
    }

    public List<OperationData> toOperationData(int docId) {
        List<OperationData> operationData = new ArrayList<>();
        for (Change c:
             changes) {
            operationData.add(new OperationData(docId, revision, OperationClass.OprationName(c.getClass()), c.offset(), c.value()));
        }
        return operationData;
    }

    public ChangesList fromOperationData(List<OperationData> operationData) {
        Change change = null;
        for (OperationData d:
             operationData) {
            String opName = d.getOpName();
            if(OperationClass.isRetain(opName)) {
                change = new Retain(d.getOpLength());
            }
            else if (OperationClass.isInsert(opName)) {
                change = new Insert(d.getOpValue());
            }
            else if (OperationClass.isDelete(opName)) {
                change = new Delete(d.getOpLength());
            }
            changes.add(change);
        }
        this.revision = operationData.get(0).getOpRevision();
        return this;
    }
}
